package com.study.prototype;

/**
 * 原型模式
 * 指定好创建对象的种类，通过拷贝这个原型来创建新的对象
 * 当需要用到一模一样的对象的时候可以用这个设计模式 而不是自己在去new一个对象一个个set属性回去
 *
 * 觉得这种很麻烦的话可以使用序列化跟反序列化的方式来处理 把要拷贝的模板对象弄成json 在用json生成新的对象即可
 *
 */
public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        BaseInfo baseInfo = new BaseInfo();
        baseInfo.setInfo("xxx");
        Product product = new Product("1","2","3","4",baseInfo);
        Product clone = product.clone();

        //这两个的Hashcode都完全不一样 很明显是两个对象
        System.out.println(product);
        System.out.println(clone);

    }
}


//通过jdk给门提供的 克隆 方法 来实现原型模式
// 浅拷贝:拷贝属性值生成一个新的对象
//  (如果模板实例里面也有引用类型且这个引用类型不实现Cloneable的话 这时候拷贝出来的实例就是共用模板实例里面的同个引用 所以一般属性带有引用的话这些引用也要实现Cloneable接口)
//  才能保证各自都是各自的不会共用
// 深拷贝:拷贝值 + 包括地址  两个实例指向的是同个内存区域
// 深拷贝浅拷贝理解 https://blog.csdn.net/qq_43842093/article/details/124539390
class Product implements Cloneable{

    private String part1;
    private String part2;
    private String part3;
    private String part4;
    private BaseInfo baseInfo;
    //... 复杂对象

    public Product (String part1,String part2,String part3,String part4,BaseInfo baseInfo){
        this.part1 = part1;
        this.part2 = part2;
        this.part3 = part3;
        this.part4 = part4;
        this.baseInfo = baseInfo;
    }

    public String getPart1() {
        return part1;
    }

    public void setPart1(String part1) {
        this.part1 = part1;
    }

    public String getPart2() {
        return part2;
    }

    public void setPart2(String part2) {
        this.part2 = part2;
    }

    public String getPart3() {
        return part3;
    }

    public void setPart3(String part3) {
        this.part3 = part3;
    }

    public String getPart4() {
        return part4;
    }

    public void setPart4(String part4) {
        this.part4 = part4;
    }

    public BaseInfo getBaseInfo() {
        return baseInfo;
    }

    public void setBaseInfo(BaseInfo baseInfo) {
        this.baseInfo = baseInfo;
    }

    @Override
    protected Product clone() throws CloneNotSupportedException { //这里面把类型强转控制下外面就可以不用控制了
        //如果当前拷贝模板对象下面有其他的引用类型的话 它们本身也得实现cloneable接口 然后在对应的实例的clone方法中还得层层调用去递归拷贝,
        //如果不实现cloneable接口或不层层调用递归拷贝的话 里面的应用是所有克隆实例共用的 容易产生问题
        //八大基本数据类型 跟 String 还有什么BigDecimal这些等 还有数组 默认都是不需要额外处理的  只有引用类型需要自己额外处理一下
        Product product = (Product) super.clone();
        BaseInfo baseInfo = product.baseInfo.clone();
        product.setBaseInfo(baseInfo);
        return product;
    }

    @Override
    public String toString() {
        return hashCode() + "--" + "Product{" +
                "part1='" + part1 + '\'' +
                ", part2='" + part2 + '\'' +
                ", part3='" + part3 + '\'' +
                ", part4='" + part4 + '\'' +
                ", baseInfo=" + baseInfo +
                '}';
    }
}

class BaseInfo implements Cloneable{
    private String info;

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    protected BaseInfo clone() throws CloneNotSupportedException {
        return ((BaseInfo) super.clone());
    }

    @Override
    public String toString() {
        return hashCode() + "--" + "BaseInfo{" +
                "info='" + info + '\'' +
                '}';
    }
}